#include <stdlib.h>
#include <stdio.h>
#include "slave.h"
#include "2d5p_aceMesh.h"
#include "task.h"
#include "ldm_malloc.h"

__thread_local volatile unsigned long get_reply,put_reply;


//__thread_local_fix double A_slave[2][BLKX+2][BLKY+2];
__thread_local_fix double *A_slave_array;
//Record the logical information of this time executed task
__thread_local_fix int dest,src,i,j,k,s_iter,s_starti,s_endi,s_startj,s_endj;
//Record the logical information of the last time executed task.
__thread_local_fix int last_iter,last_starti,last_startj;

extern double A[2][SIZEX][SIZEY];

#define alpha_d 0.0876
#define beta_d  0.0765
#define A_slave(d,i,j) A_slave_array[d*(s_endi-s_starti+2)*(s_endj-s_startj+2)+i*(s_endj-s_startj+2)+j]

void stencil_core(targs* args)
{
   long  array_size;
   int tsize, bsize, stride;
   s_iter = args->iter;
   dest = (s_iter) % 2 ; 
   src = 1 - dest;
   s_starti = args->starti;
   s_endi = args->endi;
   s_startj = args->startj;
   s_endj = args->endj;
   array_size = 2*(s_endi-s_starti+2)*(s_endj-s_startj+2);
   if(A_slave_array == NULL)
     A_slave_array = (double *)ldm_malloc(array_size * sizeof(double));
   if((s_iter-1) == last_iter && s_starti == last_starti && s_startj == last_startj)
   {
      int len, bsize, stride;
      get_reply = 0;
      //1.1 update up and down shade data
      athread_get(PE_MODE,&A[src][s_starti-1][s_startj],&A_slave((last_iter%2),0,1),(s_endj-s_startj)*8,&get_reply,0,0,0); 
      athread_get(PE_MODE,&A[src][s_endi][s_startj], &A_slave((last_iter%2),(s_endi-s_starti+1),1),(s_endj-s_startj)*8,&get_reply,0,0,0);
      //1.2 update left and right shade data
     for(i = s_starti; i < s_endi; ++i)
     {   
       athread_get(PE_MODE,&A[src][i][s_startj-1]
                   , &A_slave((last_iter%2),(i-s_starti+1),0)
                   , 8,&get_reply,0,0,0);
       athread_get(PE_MODE,&A[src][i][s_endj]
                   , &A_slave((last_iter%2),(i-s_starti+1),(s_endj-s_startj+1))
                   , 8,&get_reply,0,0,0);
     }
      while(get_reply != 2+(s_endi-s_starti)*2);
   }else{
   // 1.fetch data
   get_reply=0;  
   bsize=(s_endj-s_startj+2)*8;
   stride=(SIZEY-(s_endj-s_startj+2))*8;  //stride: from blocktail to blockhead 
   tsize= bsize*(s_endi-s_starti+2);
   athread_get(PE_MODE,&A[src][s_starti-1][s_startj-1]
                 , &A_slave(src,0,0)
                 , tsize, &get_reply
                 , 0, stride, bsize);
   
   //2.synchronize, wait for the transfer finish
   while(get_reply!=1);
   }
   //3.compute 
   for(i = 1; i < s_endi-s_starti+1; i++)
     for(j = 1; j < s_endj-s_startj+1; j++)
        A_slave(dest,i,j) = alpha_d * (A_slave(src,i,j)) + \ 
                     beta_d * (A_slave(src,(i-1),j) + A_slave(src,(i+1),j) +\
                     A_slave(src,i,(j-1)) + A_slave(src,i,(j+1)));
   last_iter = s_iter;
   last_starti = s_starti;
   last_startj = s_startj;
   //4. write back
    put_reply=0;
    for(i =  s_starti; i < s_endi; ++i)
       athread_put(PE_MODE,&A_slave(dest,(i-s_starti+1),1)
                     , &A[dest][i][s_startj]
                     ,(s_endj-s_startj)*8,&put_reply,0,0);
   while(put_reply!=(s_endi-s_starti)); 
  // ldm_free(A_slave_array,array_size * sizeof(double));
}
